home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / micrognu / part02 < prev    next >
Encoding:
Internet Message Format  |  1987-01-26  |  59.0 KB

  1. Subject:  v08i009:  A Micro-Emacs variant that resembles GNU Emacs
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: Bob Larson <seismo!usc-oberon!blarson>
  6. Mod.sources: Volume 8, Issue 9
  7. Archive-name: micrognu/Part02
  8.  
  9.  
  10. #! /bin/sh
  11. # This is a shell archive, meaning:
  12. # 1. Remove everything above the #! /bin/sh line.
  13. # 2. Save the resulting text in a file.
  14. # 3. Execute the file with /bin/sh (not csh) to create the files:
  15. #    basic.c
  16. #    buffer.c
  17. #    cinfo.c
  18. #    echo.c
  19. #    extend.c
  20. #    file.c
  21. #    match.c
  22. # This archive created: Sat Nov 15 14:59:46 1986
  23. export PATH; PATH=/bin:$PATH
  24. if test -f 'basic.c'
  25. then
  26.     echo shar: will not over-write existing file "'basic.c'"
  27. else
  28. cat << \SHAR_EOF > 'basic.c'
  29. /*
  30.  *        Basic cursor motion commands.
  31.  * 
  32.  * The routines in this file are the basic
  33.  * command functions for moving the cursor around on
  34.  * the screen, setting mark, and swapping dot with
  35.  * mark. Only moves between lines, which might make the
  36.  * current buffer framing bad, are hard.
  37.  */
  38. #include    "def.h"
  39.  
  40. /*
  41.  * Go to beginning of line.
  42.  */
  43. /*ARGSUSED*/
  44. gotobol(f, n, k) {
  45.     curwp->w_doto  = 0;
  46.     return (TRUE);
  47. }
  48.  
  49. /*
  50.  * Move cursor backwards. Do the
  51.  * right thing if the count is less than
  52.  * 0. Error if you try to move back from
  53.  * the beginning of the buffer.
  54.  */
  55. /*ARGSUSED*/
  56. backchar(f, n, k) register int n; {
  57.     register LINE    *lp;
  58.  
  59.     if (n < 0)
  60.         return (forwchar(f, -n, k));
  61.     while (n--) {
  62.         if (curwp->w_doto == 0) {
  63.             if ((lp=lback(curwp->w_dotp)) == curbp->b_linep) {
  64.                 if (k != KRANDOM)
  65.                     ewprintf("Beginning of buffer");
  66.                 return (FALSE);
  67.             }
  68.             curwp->w_dotp  = lp;
  69.             curwp->w_doto  = llength(lp);
  70.             curwp->w_flag |= WFMOVE;
  71.         } else
  72.             curwp->w_doto--;
  73.     }
  74.     return (TRUE);
  75. }
  76.  
  77. /*
  78.  * Go to end of line.
  79.  */
  80. /*ARGSUSED*/
  81. gotoeol(f, n, k) {
  82.     curwp->w_doto  = llength(curwp->w_dotp);
  83.     return (TRUE);
  84. }
  85.  
  86. /*
  87.  * Move cursor forwards. Do the
  88.  * right thing if the count is less than
  89.  * 0. Error if you try to move forward
  90.  * from the end of the buffer.
  91.  */
  92. /*ARGSUSED*/
  93. forwchar(f, n, k) register int n; {
  94.     if (n < 0)
  95.         return (backchar(f, -n, k));
  96.     while (n--) {
  97.         if (curwp->w_doto == llength(curwp->w_dotp)) {
  98.             if (curwp->w_dotp == curbp->b_linep) {
  99.                 if (k != KRANDOM)
  100.                     ewprintf("End of buffer");
  101.                 return (FALSE);
  102.             }
  103.             curwp->w_dotp  = lforw(curwp->w_dotp);
  104.             curwp->w_doto  = 0;
  105.             curwp->w_flag |= WFMOVE;
  106.         } else
  107.             curwp->w_doto++;
  108.     }
  109.     return (TRUE);
  110. }
  111.  
  112. /*
  113.  * Go to the beginning of the
  114.  * buffer. Setting WFHARD is conservative,
  115.  * but almost always the case.
  116.  */
  117. gotobob(f, n, k) {
  118.     (VOID) setmark(f, n, k) ;
  119.     curwp->w_dotp  = lforw(curbp->b_linep);
  120.     curwp->w_doto  = 0;
  121.     curwp->w_flag |= WFHARD;
  122.     return (TRUE);
  123. }
  124.  
  125. /*
  126.  * Go to the end of the buffer.
  127.  * Setting WFHARD is conservative, but
  128.  * almost always the case.
  129.  */
  130. gotoeob(f, n, k) {
  131.     (VOID) setmark(f, n, k) ;
  132.     curwp->w_dotp  = curbp->b_linep;
  133.     curwp->w_doto  = 0;
  134.     curwp->w_flag |= WFHARD;
  135.     return (TRUE);
  136. }
  137.  
  138. /*
  139.  * Move forward by full lines.
  140.  * If the number of lines to move is less
  141.  * than zero, call the backward line function to
  142.  * actually do it. The last command controls how
  143.  * the goal column is set.
  144.  */
  145. /*ARGSUSED*/
  146. forwline(f, n, k) {
  147.     register LINE    *dlp;
  148.  
  149.     if (n < 0)
  150.         return (backline(f, -n, KRANDOM));
  151.     if ((lastflag&CFCPCN) == 0)        /* Fix goal.        */
  152.         setgoal();
  153.     thisflag |= CFCPCN;
  154.     dlp = curwp->w_dotp;
  155.     while (n-- && dlp!=curbp->b_linep)
  156.         dlp = lforw(dlp);
  157.     curwp->w_dotp  = dlp;
  158.     curwp->w_doto  = getgoal(dlp);
  159.     curwp->w_flag |= WFMOVE;
  160.     return (TRUE);
  161. }
  162.  
  163. /*
  164.  * This function is like "forwline", but
  165.  * goes backwards. The scheme is exactly the same.
  166.  * Check for arguments that are less than zero and
  167.  * call your alternate. Figure out the new line and
  168.  * call "movedot" to perform the motion.
  169.  */
  170. /*ARGSUSED*/
  171. backline(f, n, k) {
  172.     register LINE    *dlp;
  173.  
  174.     if (n < 0)
  175.         return (forwline(f, -n, KRANDOM));
  176.     if ((lastflag&CFCPCN) == 0)        /* Fix goal.        */
  177.         setgoal();
  178.     thisflag |= CFCPCN;
  179.     dlp = curwp->w_dotp;
  180.     while (n-- && lback(dlp)!=curbp->b_linep)
  181.         dlp = lback(dlp);
  182.     curwp->w_dotp  = dlp;
  183.     curwp->w_doto  = getgoal(dlp);
  184.     curwp->w_flag |= WFMOVE;
  185.     return (TRUE);
  186. }
  187.  
  188. /*
  189.  * Set the current goal column,
  190.  * which is saved in the external variable "curgoal",
  191.  * to the current cursor column. The column is never off
  192.  * the edge of the screen; it's more like display then
  193.  * show position.
  194.  */
  195. setgoal() {
  196.  
  197.     curgoal = getcolpos() - 1;        /* Get the position.    */
  198.     if (curgoal >= ncol)            /* Chop to tty width.    */
  199.         curgoal = ncol-1;
  200. }
  201.  
  202. /*
  203.  * This routine looks at a line (pointed
  204.  * to by the LINE pointer "dlp") and the current
  205.  * vertical motion goal column (set by the "setgoal"
  206.  * routine above) and returns the best offset to use
  207.  * when a vertical motion is made into the line.
  208.  */
  209. getgoal(dlp) register LINE *dlp; {
  210.     register int    c;
  211.     register int    col;
  212.     register int    newcol;
  213.     register int    dbo;
  214.  
  215.     col = 0;
  216.     dbo = 0;
  217.     while (dbo != llength(dlp)) {
  218.         c = lgetc(dlp, dbo);
  219.         newcol = col;
  220.         if (c == '\t')
  221.             newcol |= 0x07;
  222.         else if (ISCTRL(c) != FALSE)
  223.             ++newcol;
  224.         ++newcol;
  225.         if (newcol > curgoal)
  226.             break;
  227.         col = newcol;
  228.         ++dbo;
  229.     }
  230.     return (dbo);
  231. }
  232.  
  233. /*
  234.  * Scroll forward by a specified number
  235.  * of lines, or by a full page if no argument.
  236.  * The "2" is the window overlap (this is the default
  237.  * value from ITS EMACS). Because the top line in
  238.  * the window is zapped, we have to do a hard
  239.  * update and get it back.
  240.  */
  241. /*ARGSUSED*/
  242. forwpage(f, n, k) register int n; {
  243.     register LINE    *lp;
  244.  
  245.     if (f == FALSE) {
  246.         n = curwp->w_ntrows - 2;    /* Default scroll.    */
  247.         if (n <= 0)            /* Forget the overlap    */
  248.             n = 1;            /* if tiny window.    */
  249.     } else if (n < 0)
  250.         return (backpage(f, -n, KRANDOM));
  251. #ifdef    CVMVAS
  252.     else                    /* Convert from pages    */
  253.         n *= curwp->w_ntrows;        /* to lines.        */
  254. #endif
  255.     lp = curwp->w_linep;
  256.     while (n-- && lp!=curbp->b_linep)
  257.         lp = lforw(lp);
  258.     curwp->w_linep = lp;
  259.     curwp->w_dotp  = lp;
  260.     curwp->w_doto  = 0;
  261.     curwp->w_flag |= WFHARD;
  262.     return (TRUE);
  263. }
  264.  
  265. /*
  266.  * This command is like "forwpage",
  267.  * but it goes backwards. The "2", like above,
  268.  * is the overlap between the two windows. The
  269.  * value is from the ITS EMACS manual. The
  270.  * hard update is done because the top line in
  271.  * the window is zapped.
  272.  */
  273. /*ARGSUSED*/
  274. backpage(f, n, k) register int n; {
  275.     register LINE    *lp;
  276.  
  277.     if (f == FALSE) {
  278.         n = curwp->w_ntrows - 2;    /* Default scroll.    */
  279.         if (n <= 0)            /* Don't blow up if the    */
  280.             n = 1;            /* window is tiny.    */
  281.     } else if (n < 0)
  282.         return (forwpage(f, -n, KRANDOM));
  283. #ifdef    CVMVAS
  284.     else                    /* Convert from pages    */
  285.         n *= curwp->w_ntrows;        /* to lines.        */
  286. #endif
  287.     lp = curwp->w_linep;
  288.     while (n-- && lback(lp)!=curbp->b_linep)
  289.         lp = lback(lp);
  290.     curwp->w_linep = lp;
  291.     curwp->w_dotp  = lp;
  292.     curwp->w_doto  = 0;
  293.     curwp->w_flag |= WFHARD;
  294.     return (TRUE);
  295. }
  296.  
  297. /*
  298.  * Page the other window. Check to make sure it exists, then
  299.  * nextwind, forwpage and prevwind.
  300.  */
  301. pagenext(f, n, k) {
  302.     if (wheadp->w_wndp == NULL) {
  303.         ewprintf("No other window");
  304.         return FALSE;
  305.     }
  306.     (VOID) nextwind(f, n, k);
  307.     (VOID) forwpage(f, n, k);
  308.     (VOID) prevwind(f, n, k);
  309.     return TRUE;
  310. }
  311.  
  312. /*
  313.  * Set the mark in the current window
  314.  * to the value of dot. A message is written to
  315.  * the echo line unless we are running in a keyboard
  316.  * macro, when it would be silly.
  317.  */
  318. /*ARGSUSED*/
  319. setmark(f, n, k) {
  320.     isetmark();
  321.     if (kbdmop == NULL)
  322.         ewprintf("Mark set");
  323.     return (TRUE);
  324. }
  325.  
  326. /* 
  327.  * Internal set mark routine, used by other functions (daveb).
  328.  */
  329. isetmark()
  330. {
  331.     curwp->w_markp = curwp->w_dotp;
  332.     curwp->w_marko = curwp->w_doto;
  333. }
  334.  
  335. /*
  336.  * Swap the values of "dot" and "mark" in
  337.  * the current window. This is pretty easy, because
  338.  * all of the hard work gets done by the standard routine
  339.  * that moves the mark about. The only possible
  340.  * error is "no mark".
  341.  */
  342. /*ARGSUSED*/
  343. swapmark(f, n, k) {
  344.     register LINE    *odotp;
  345.     register int    odoto;
  346.  
  347.     if (curwp->w_markp == NULL) {
  348.         ewprintf("No mark in this window");
  349.         return (FALSE);
  350.     }
  351.     odotp = curwp->w_dotp;
  352.     odoto = curwp->w_doto;
  353.     curwp->w_dotp  = curwp->w_markp;
  354.     curwp->w_doto  = curwp->w_marko;
  355.     curwp->w_markp = odotp;
  356.     curwp->w_marko = odoto;
  357.     curwp->w_flag |= WFMOVE;
  358.     return (TRUE);
  359. }
  360.  
  361. /*
  362.  * Go to a specific line, mostly for
  363.  * looking up errors in C programs, which give the
  364.  * error a line number. If an argument is present, then
  365.  * it is the line number, else prompt for a line number
  366.  * to use.
  367.  */
  368. /*ARGSUSED*/
  369. gotoline(f, n, k) register int n; {
  370.     register LINE    *clp;
  371.     register int    s;
  372.     char        buf[32];
  373.  
  374.     if (f == FALSE) {
  375.         if ((s=ereply("Goto line: ", buf, sizeof(buf))) != TRUE)
  376.             return (s);
  377.         n = atoi(buf);
  378.     }
  379.  
  380.     clp = lforw(curbp->b_linep);        /* "clp" is first line    */
  381.     while (n > 1) {
  382.         if (lforw(clp) == curbp->b_linep) break;
  383.         clp = lforw(clp);
  384.         --n;
  385.     }
  386.     curwp->w_dotp = clp;
  387.     curwp->w_doto = 0;
  388.     curwp->w_flag |= WFMOVE;
  389.     return (TRUE);
  390. }
  391. SHAR_EOF
  392. fi # end of overwriting check
  393. if test -f 'buffer.c'
  394. then
  395.     echo shar: will not over-write existing file "'buffer.c'"
  396. else
  397. cat << \SHAR_EOF > 'buffer.c'
  398. /*
  399.  *        Buffer handling.
  400.  */
  401. #include    "def.h"
  402.  
  403. /*
  404.  * Attach a buffer to a window. The
  405.  * values of dot and mark come from the buffer
  406.  * if the use count is 0. Otherwise, they come
  407.  * from some other window.
  408.  */
  409. /*ARGSUSED*/
  410. usebuffer(f, n, k) {
  411.     register BUFFER    *bp;
  412.     register int    s;
  413.     char        bufn[NBUFN];
  414.  
  415.     /* Get buffer to use from user */
  416.     if (curbp->b_altb != NULL)
  417.         s=eread("Switch to buffer: (default %s) ", bufn, NBUFN,
  418.              EFNEW|EFBUF, 
  419. #ifdef    VARARGS
  420.              curbp->b_altb->b_bname
  421. #else
  422.              &(curbp->b_altb->b_bname), (char *) NULL
  423. #endif
  424.              ) ;
  425.     else
  426.         s=eread("Switch to buffer: ", bufn, NBUFN, EFNEW|EFBUF
  427. #ifndef VARARGS
  428.              ,(char *) NULL
  429. #endif
  430.              );
  431.     if (s == ABORT) return (s);
  432.     if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb ;
  433.     else if ((bp=bfind(bufn, TRUE)) == NULL) return (FALSE);
  434.  
  435.     /* and put it in current window */
  436.     curbp = bp;
  437.     return showbuffer(bp, curwp, WFFORCE|WFHARD);
  438. }
  439.  
  440. /*
  441.  * pop to buffer asked for by the user.
  442.  */
  443. /*ARGSUSED*/
  444. poptobuffer(f, n, k) {
  445.     register BUFFER    *bp;
  446.     register WINDOW    *wp;
  447.     register int    s;
  448.     char        bufn[NBUFN];
  449.  
  450.     /* Get buffer to use from user */
  451.     if (curbp->b_altb != NULL)
  452.         s=eread("Switch to buffer in other window: (default %s) ",
  453.              bufn, NBUFN, EFNEW|EFBUF, 
  454. #ifdef    VARARGS
  455.              curbp->b_altb->b_bname
  456. #else
  457.              &(curbp->b_altb->b_bname) ,(char *) NULL
  458. #endif
  459.              ) ;
  460.     else
  461.         s=eread("Switch to buffer in other window: ", bufn, NBUFN,
  462.         EFNEW|EFBUF
  463. #ifndef VARARGS
  464.         , (char *) NULL
  465. #endif
  466.         ) ;
  467.     if (s == ABORT) return (s);
  468.     if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb ;
  469.     else if ((bp=bfind(bufn, TRUE)) == NULL) return (FALSE);
  470.  
  471.     /* and put it in a new window */
  472.     if ((wp = popbuf(bp)) == NULL) return FALSE;
  473.     curbp = bp;
  474.     curwp = wp;
  475.     return TRUE;
  476. }
  477.  
  478. /*
  479.  * Dispose of a buffer, by name.
  480.  * Ask for the name. Look it up (don't get too
  481.  * upset if it isn't there at all!). Clear the buffer (ask
  482.  * if the buffer has been changed). Then free the header
  483.  * line and the buffer header. Bound to "C-X K".
  484.  */
  485. /*ARGSUSED*/
  486. killbuffer(f, n, k) {
  487.     register BUFFER    *bp;
  488.     register BUFFER    *bp1;
  489.     register BUFFER    *bp2;
  490.     register WINDOW    *wp;
  491.     register int    s;
  492.     char        bufn[NBUFN];
  493.  
  494.     if ((s=eread("Kill buffer: (default %s) ", bufn, NBUFN, EFNEW|EFBUF,
  495. #ifdef    VARARGS
  496.             curbp->b_bname
  497. #else
  498.             &(curbp->b_bname)
  499. #endif
  500.             )) == ABORT) return (s);
  501.     else if (s == FALSE) bp = curbp ;
  502.     else if ((bp=bfind(bufn, FALSE)) == NULL) return FALSE;
  503.  
  504.     if (bp->b_nwnd != 0) {
  505.         if ((bp1 = bp->b_altb) == NULL) return FALSE;
  506.         if (bclear(bp) != TRUE) return TRUE;
  507.         for (wp = wheadp; bp->b_nwnd > 0; wp = wp->w_wndp) {
  508.             /* Special case - could use showbuf, but don't */
  509.             if (wp->w_bufp == bp) {
  510.                 --bp->b_nwnd;
  511.                 ++bp1->b_nwnd;
  512.                 wp->w_bufp  = bp1 ;
  513.                 wp->w_dotp  = bp1->b_dotp;
  514.                 wp->w_doto  = bp1->b_doto;
  515.                 wp->w_markp = bp1->b_markp;
  516.                 wp->w_marko = bp1->b_marko;
  517.                 wp->w_linep = bp1->b_linep;
  518.                 wp->w_flag |= WFMODE|WFFORCE|WFHARD;
  519.             }
  520.         }
  521.     }
  522.     else if (bclear(bp) != TRUE) return TRUE;
  523.     if (bp == curbp) curbp = bp->b_altb;
  524.     free((char *) bp->b_linep);        /* Release header line.    */
  525.     bp1 = NULL;                /* Find the header.    */
  526.     bp2 = bheadp;
  527.     while (bp2 != bp) {
  528.         if (bp2->b_altb == bp) 
  529.             bp2->b_altb = (bp->b_altb == bp2) ? NULL : bp->b_altb;
  530.         bp1 = bp2;
  531.         bp2 = bp2->b_bufp;
  532.     }
  533.     bp2 = bp2->b_bufp;            /* Next one in chain.    */
  534.     if (bp1 == NULL)            /* Unlink it.        */
  535.         bheadp = bp2;
  536.     else
  537.         bp1->b_bufp = bp2;
  538.     while (bp2 != NULL) {            /* Finish with altb's    */
  539.         if (bp2->b_altb == bp) 
  540.             bp2->b_altb = (bp->b_altb == bp2) ? NULL : bp->b_altb;
  541.         bp2 = bp2->b_bufp;
  542.     }
  543.     free(bp->b_bname);        /* Release name block    */
  544.     free((char *) bp);            /* Release buffer block    */
  545.     return (TRUE);
  546. }
  547.  
  548. /*
  549.  * Save some buffers - just call anycb with the arg flag.
  550.  */
  551. /*ARGSUSED*/
  552. savebuffers(f, n, k) {
  553.     if (anycb(f) == ABORT) return ABORT;
  554.     return TRUE;
  555. }
  556.  
  557. /*
  558.  * Display the buffer list. This is done
  559.  * in two parts. The "makelist" routine figures out
  560.  * the text, and puts it in a buffer. "popbuf"
  561.  * then pops the data onto the screen. Bound to
  562.  * "C-X C-B".
  563.  */
  564. /*ARGSUSED*/
  565. listbuffers(f, n, k) {
  566.     register BUFFER    *bp;
  567.     register WINDOW *wp;
  568.     BUFFER         *makelist();
  569.     WINDOW        *popb();
  570.  
  571.     if ((bp=makelist()) == NULL || (wp=popbuf(bp)) == NULL)
  572.         return FALSE;
  573.     wp->w_dotp = bp->b_dotp;    /* fix up if window already on screen */
  574.     wp->w_doto = bp->b_doto;
  575.     return TRUE;
  576. }
  577.  
  578. /*
  579.  * This routine rebuilds the text for the
  580.  * list buffers command. Return TRUE if
  581.  * everything works. Return FALSE if there
  582.  * is an error (if there is no memory).
  583.  */
  584. BUFFER *
  585. makelist() {
  586.     register char    *cp1;
  587.     register char    *cp2;
  588.     register int    c;
  589.     register BUFFER    *bp;
  590.     register LINE    *lp;
  591.     register RSIZE    nbytes;
  592.     BUFFER        *blp;
  593.     char        b[6+1];
  594.     char        line[128];
  595.     
  596.     if ((blp = bfind("*Buffer List*", TRUE)) == NULL) return NULL;
  597.     if (bclear(blp) != TRUE) return NULL;
  598.     blp->b_flag &= ~BFCHG;            /* Blow away old.    */
  599.  
  600.     (VOID) strcpy(line, " MR Buffer");
  601.     cp1 = line + 10;
  602.     while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
  603.     (VOID) strcpy(cp1, "Size   File");
  604.     if (addline(blp, line) == FALSE) return NULL;
  605.     (VOID) strcpy(line, " -- ------");
  606.     cp1 = line + 10;
  607.     while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
  608.     (VOID) strcpy(cp1, "----   ----");
  609.     if (addline(blp, line) == FALSE) return NULL;
  610.     bp = bheadp;                /* For all buffers    */
  611.     while (bp != NULL) {
  612.         cp1 = &line[0];            /* Start at left edge    */
  613.         *cp1++ = (bp == curbp) ? '.' : ' ';
  614.         *cp1++ = ((bp->b_flag&BFCHG) != 0) ? '*' : ' ';
  615.         *cp1++ = ' ';            /* Gap.            */
  616.         *cp1++ = ' ';
  617.         cp2 = &bp->b_bname[0];        /* Buffer name        */
  618.         while ((c = *cp2++) != 0)
  619.             *cp1++ = c;
  620.         while (cp1 < &line[4+NBUFN+1])
  621.             *cp1++ = ' ';        
  622.         nbytes = 0;            /* Count bytes in buf.    */
  623.         if (bp != blp) {
  624.             lp = lforw(bp->b_linep);
  625.             while (lp != bp->b_linep) {
  626.                 nbytes += llength(lp)+1;
  627.                 lp = lforw(lp);
  628.             }
  629.         }
  630.         (VOID) itor(b, 6, nbytes);    /* 6 digit buffer size.    */
  631.         cp2 = &b[0];
  632.         while ((c = *cp2++) != 0)
  633.             *cp1++ = c;
  634.         *cp1++ = ' ';            /* Gap..            */
  635.         cp2 = &bp->b_fname[0];        /* File name        */
  636.         if (*cp2 != 0) {
  637.             while ((c = *cp2++) != 0) {
  638.                 if (cp1 < &line[128-1])
  639.                     *cp1++ = c;
  640.             }
  641.         }
  642.         *cp1 = 0;            /* Add to the buffer.    */
  643.         if (addline(blp, line) == FALSE)
  644.             return NULL;
  645.         bp = bp->b_bufp;
  646.     }
  647.     blp->b_dotp = lforw(blp->b_linep);    /* put dot at beginning of buffer */
  648.     blp->b_doto = 0;
  649.     return blp;                /* All done        */
  650. }
  651.  
  652. /*
  653.  * Used above.
  654.  */
  655. static itor(buf, width, num)
  656. register char buf[]; register int width; register RSIZE num; {
  657.     register RSIZE r;
  658.  
  659.     if (num / 10 == 0) {
  660.         buf[0] = (num % 10) + '0';
  661.         for (r = 1; r < width; buf[r++] = ' ')
  662.             ;
  663.         buf[width] = '\0';
  664.         return 1;
  665.     } else {
  666.         buf[r = itor(buf, width, num / (RSIZE)10)] = 
  667.                 (num % (RSIZE)10) + '0';
  668.         return r + 1;
  669.     }
  670. }
  671.  
  672. /*
  673.  * The argument "text" points to
  674.  * a string. Append this line to the
  675.  * buffer. Handcraft the EOL
  676.  * on the end. Return TRUE if it worked and
  677.  * FALSE if you ran out of room.
  678.  */
  679. addline(bp, text) register BUFFER *bp; char *text; {
  680.     register LINE    *lp;
  681.     register int    i;
  682.     register int    ntext;
  683.  
  684.     ntext = strlen(text);
  685.     if ((lp=lalloc((RSIZE) ntext)) == NULL)
  686.         return (FALSE);
  687.     for (i=0; i<ntext; ++i)
  688.         lputc(lp, i, text[i]);
  689.     bp->b_linep->l_bp->l_fp = lp;        /* Hook onto the end    */
  690.     lp->l_bp = bp->b_linep->l_bp;
  691.     bp->b_linep->l_bp = lp;
  692.     lp->l_fp = bp->b_linep;
  693.     if (bp->b_dotp == bp->b_linep)        /* If "." is at the end    */
  694.         bp->b_dotp = lp;        /* move it to new line    */
  695.     if (bp->b_markp == bp->b_linep)        /* ditto for mark     */
  696.         bp->b_markp = lp;
  697.     return (TRUE);
  698. }
  699.  
  700. /*
  701.  * Look through the list of buffers, giving the user
  702.  * a chance to save them.  Return TRUE if there are
  703.  * any changed buffers afterwards. Buffers that don't
  704.  * have an associated file don't count. Return FALSE
  705.  * if there are no changed buffers.
  706.  */
  707. anycb(f) {
  708.     register BUFFER    *bp;
  709.     register int    s = FALSE, save = FALSE;
  710.     char        prompt[NFILEN + 11];
  711.  
  712.     for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
  713.         if (*(bp->b_fname) != '\0'
  714.         &&  (bp->b_flag&BFCHG) != 0) {
  715.             (VOID) strcpy(prompt, "Save file ");
  716.             (VOID) strcpy(prompt + 10, bp->b_fname);
  717.             if ((f == TRUE || (save = eyorn(prompt)) == TRUE)
  718.             &&  writeout(bp, bp->b_fname) == TRUE) {
  719.                 bp->b_flag &= ~BFCHG;
  720.                 upmodes(bp);
  721.             } else s = TRUE;
  722.             if (save == ABORT) return (save);
  723.             save = TRUE;
  724.         }
  725.     }
  726.     if (save == FALSE && kbdmop == NULL)
  727.         ewprintf("(No files need saving)");
  728.     return s;
  729. }
  730.  
  731. /*
  732.  * Search for a buffer, by name.
  733.  * If not found, and the "cflag" is TRUE,
  734.  * create a buffer and put it in the list of
  735.  * all buffers. Return pointer to the BUFFER
  736.  * block for the buffer.
  737.  */
  738. BUFFER    *
  739. bfind(bname, cflag) register char *bname; {
  740.     register BUFFER    *bp;
  741.     char        *malloc();
  742.     register LINE    *lp;
  743.  
  744.     bp = bheadp;
  745.     while (bp != NULL) {
  746.         if (strcmp(bname, bp->b_bname) == 0)
  747.             return (bp);
  748.         bp = bp->b_bufp;
  749.     }
  750.     if (cflag!=TRUE) return NULL;
  751.     /*NOSTRICT*/
  752.     if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) {
  753.         ewprintf("Can't get %d bytes", sizeof(BUFFER));
  754.         return NULL;
  755.     }
  756.     if ((bp->b_bname=malloc(strlen(bname)+1)) == NULL) {
  757.         ewprintf("Can't get %d bytes", strlen(bname)+1);
  758.         free((char *) bp);
  759.         return NULL;
  760.     }
  761.     if ((lp=lalloc((RSIZE) 0)) == NULL) {
  762.         free(bp->b_bname);
  763.         free((char *) bp);
  764.         return NULL;
  765.     }
  766.     bp->b_altb = bp->b_bufp  = NULL;
  767.     bp->b_dotp  = lp;
  768.     bp->b_doto  = 0;
  769.     bp->b_markp = NULL;
  770.     bp->b_marko = 0;
  771.     bp->b_flag  = 0;
  772.     bp->b_nwnd  = 0;
  773.     bp->b_linep = lp;
  774.     (VOID) strcpy(bp->b_fname, "");
  775.     (VOID) strcpy(bp->b_bname, bname);
  776.     lp->l_fp = lp;
  777.     lp->l_bp = lp;
  778.     bp->b_bufp = bheadp;
  779.     bheadp = bp;
  780.     return (bp);
  781. }
  782.  
  783. /*
  784.  * This routine blows away all of the text
  785.  * in a buffer. If the buffer is marked as changed
  786.  * then we ask if it is ok to blow it away; this is
  787.  * to save the user the grief of losing text. The
  788.  * window chain is nearly always wrong if this gets
  789.  * called; the caller must arrange for the updates
  790.  * that are required. Return TRUE if everything
  791.  * looks good.
  792.  */
  793. bclear(bp) register BUFFER *bp; {
  794.     register LINE    *lp;
  795.     register int    s;
  796.     
  797.     if ((bp->b_flag&BFCHG) != 0        /* Changed.        */
  798.     && (s=eyesno("Buffer modified; kill anyway")) != TRUE)
  799.         return (s);
  800.     bp->b_flag  &= ~BFCHG;            /* Not changed        */
  801.     while ((lp=lforw(bp->b_linep)) != bp->b_linep)
  802.         lfree(lp);
  803.     bp->b_dotp  = bp->b_linep;        /* Fix "."        */
  804.     bp->b_doto  = 0;
  805.     bp->b_markp = NULL;            /* Invalidate "mark"    */
  806.     bp->b_marko = 0;
  807.     return (TRUE);
  808. }
  809.  
  810. /*
  811.  * Display the given buffer in the given window. Flags indicated
  812.  * action on redisplay.
  813.  */
  814. showbuffer(bp, wp, flags) register BUFFER *bp; register WINDOW *wp; {
  815.     register BUFFER    *obp;
  816.     register WINDOW    *owp;
  817.  
  818.     if (wp->w_bufp == bp) {            /* Easy case!    */
  819.         wp->w_flag |= flags;
  820.         return TRUE ;
  821.     }
  822.  
  823.     /* First, dettach the old buffer from the window */
  824.     if ((bp->b_altb = obp = wp->w_bufp) != NULL) {
  825.         if (--obp->b_nwnd == 0) {
  826.             obp->b_dotp  = wp->w_dotp;
  827.             obp->b_doto  = wp->w_doto;
  828.             obp->b_markp = wp->w_markp;
  829.             obp->b_marko = wp->w_marko;
  830.         }
  831.     }
  832.  
  833.     /* Now, attach the new buffer to the window */
  834.     wp->w_bufp = bp;
  835.  
  836.     if (bp->b_nwnd++ == 0) {        /* First use.        */
  837.         wp->w_dotp  = bp->b_dotp;
  838.         wp->w_doto  = bp->b_doto;
  839.         wp->w_markp = bp->b_markp;
  840.         wp->w_marko = bp->b_marko;
  841.     } else
  842.     /* already on screen, steal values from other window */
  843.         for (owp = wheadp; owp != NULL; owp = wp->w_wndp)
  844.             if (wp->w_bufp == bp && owp != wp) {
  845.                 wp->w_dotp  = owp->w_dotp;
  846.                 wp->w_doto  = owp->w_doto;
  847.                 wp->w_markp = owp->w_markp;
  848.                 wp->w_marko = owp->w_marko;
  849.                 break;
  850.             }
  851.     wp->w_flag |= WFMODE|flags;
  852.     return TRUE;
  853. }
  854.  
  855. /*
  856.  * Pop the buffer we got passed onto the screen.
  857.  * Returns a status.
  858.  */
  859. WINDOW *
  860. popbuf(bp) register BUFFER *bp; {
  861.     register WINDOW    *wp;
  862.  
  863.     if (bp->b_nwnd == 0) {        /* Not on screen yet.    */
  864.         if ((wp=wpopup()) == NULL) return NULL;
  865.     } else
  866.         for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
  867.             if (wp->w_bufp == bp) {
  868.                 wp->w_flag |= WFHARD|WFFORCE;
  869.                 return wp ;
  870.             }
  871.     if (showbuffer(bp, wp, WFHARD) != TRUE) return NULL;
  872.     return wp;
  873. }
  874.  
  875. /*
  876.  * Insert another buffer at dot.  Very useful.
  877.  */
  878.  
  879. bufferinsert(f, n, k)
  880. {
  881.     register BUFFER *bp;
  882.     register LINE    *clp;
  883.     register int    clo;
  884.     register int    nline;
  885.     int        s;
  886.     char        bufn[NBUFN];
  887.  
  888.     /* Get buffer to use from user */
  889.     if (curbp->b_altb != NULL)
  890.         s=eread("Insert buffer: (default %s) ", bufn, NBUFN,
  891.              EFNEW|EFBUF, &(curbp->b_altb->b_bname),
  892.              (char *) NULL) ;
  893.     else
  894.         s=eread("Insert buffer: ", bufn, NBUFN, EFNEW|EFBUF,
  895.              (char *) NULL) ;
  896.     if (s == ABORT) return (s);
  897.     if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb;
  898.     else if ((bp=bfind(bufn, FALSE)) == NULL) return (FALSE);
  899.  
  900.     if (bp==curbp) {
  901.         ewprintf("Cannot insert buffer into self");
  902.         return (FALSE);
  903.     }
  904.  
  905.     /* insert the buffer */    
  906.     nline = 0;
  907.     for (clp = lforw(bp->b_linep); clp != bp->b_linep; clp = lforw(clp)) {
  908.         for (clo = 0; clo < llength(clp); clo++)
  909.             if (linsert((RSIZE)1, lgetc(clp, clo)) == FALSE)
  910.                 return (FALSE);
  911.         if (newline(FALSE, 1, KRANDOM) == FALSE) /* fake newline */
  912.             return (FALSE);
  913.         nline++;
  914.     }
  915.     if (kbdmop==NULL) {
  916.         if (nline == 1)
  917.             ewprintf("[Inserted 1 line]");
  918.         else
  919.             ewprintf("[Inserted %d lines]", nline);
  920.     }
  921.  
  922.     clp = curwp->w_linep;            /* cosmetic adjustment */
  923.     if (curwp->w_dotp == clp) {        /* for offscreen insert */
  924.         while (nline-- && lback(clp)!=curbp->b_linep)
  925.             clp = lback(clp);
  926.         curwp->w_linep = clp;        /* adjust framing.    */
  927.         curwp->w_flag |= WFHARD;
  928.     }
  929.     return (TRUE);
  930. }
  931.  
  932. /*
  933.  * Turn off the dirty bit on this buffer.
  934.  */
  935. /*ARGSUSED*/
  936. notmodified(f, n, k)
  937. {
  938.     register WINDOW *wp;
  939.     
  940.     curbp->b_flag &= ~BFCHG;
  941.     wp = wheadp;                /* Update mode lines.    */
  942.     while (wp != NULL) {
  943.         if (wp->w_bufp == curbp)
  944.             wp->w_flag |= WFMODE;
  945.         wp = wp->w_wndp;
  946.     }
  947.     ewprintf("Modification-flag cleared");
  948.     return (TRUE);
  949. }
  950. SHAR_EOF
  951. fi # end of overwriting check
  952. if test -f 'cinfo.c'
  953. then
  954.     echo shar: will not over-write existing file "'cinfo.c'"
  955. else
  956. cat << \SHAR_EOF > 'cinfo.c'
  957. /*
  958.  *        Character class tables.
  959.  * Do it yourself character classification
  960.  * macros, that understand the multinational character set,
  961.  * and let me ask some questions the standard macros (in
  962.  * ctype.h) don't let you ask.
  963.  */
  964. #include    "def.h"
  965.  
  966. /*
  967.  * This table, indexed by a character drawn
  968.  * from the 256 member character set, is used by my
  969.  * own character type macros to answer questions about the
  970.  * type of a character. It handles the full multinational
  971.  * character set, and lets me ask some questions that the
  972.  * standard "ctype" macros cannot ask.
  973.  */
  974. char    cinfo[256] = {
  975.     _C,        _C,        _C,        _C,    /* 0x0X    */
  976.     _C,        _C,        _C,        _C,
  977.     _C,        _C,        _C,        _C,
  978.     _C,        _C,        _C,        _C,
  979.     _C,        _C,        _C,        _C,    /* 0x1X    */
  980.     _C,        _C,        _C,        _C,
  981.     _C,        _C,        _C,        _C,
  982.     _C,        _C,        _C,        _C,
  983.     0,        _P,        0,        0,    /* 0x2X    */
  984.     _W,        _W,        0,        _W,
  985.     0,        0,        0,        0,
  986.     0,        0,        _P,        0,
  987.     _W,        _W,        _W,        _W,    /* 0x3X    */
  988.     _W,        _W,        _W,        _W,
  989.     _W,        _W,        0,        0,
  990.     0,        0,        0,        _P,
  991.     0,        _U|_W,        _U|_W,        _U|_W,    /* 0x4X    */
  992.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  993.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  994.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  995.     _U|_W,        _U|_W,        _U|_W,        _U|_W,    /* 0x5X    */
  996.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  997.     _U|_W,        _U|_W,        _U|_W,        0,
  998.     0,        0,        0,        0,
  999.     0,        _L|_W,        _L|_W,        _L|_W,    /* 0x6X    */
  1000.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  1001.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  1002.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  1003.     _L|_W,        _L|_W,        _L|_W,        _L|_W,    /* 0x7X    */
  1004.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  1005.     _L|_W,        _L|_W,        _L|_W,        0,
  1006.     0,        0,        0,        _C,
  1007.     0,        0,        0,        0,    /* 0x8X    */
  1008.     0,        0,        0,        0,
  1009.     0,        0,        0,        0,
  1010.     0,        0,        0,        0,
  1011.     0,        0,        0,        0,    /* 0x9X    */
  1012.     0,        0,        0,        0,
  1013.     0,        0,        0,        0,
  1014.     0,        0,        0,        0,
  1015.     0,        0,        0,        0,    /* 0xAX    */
  1016.     0,        0,        0,        0,
  1017.     0,        0,        0,        0,
  1018.     0,        0,        0,        0,
  1019.     0,        0,        0,        0,    /* 0xBX    */
  1020.     0,        0,        0,        0,
  1021.     0,        0,        0,        0,
  1022.     0,        0,        0,        0,
  1023.     _U|_W,        _U|_W,        _U|_W,        _U|_W,    /* 0xCX    */
  1024.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  1025.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  1026.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  1027.     0,        _U|_W,        _U|_W,        _U|_W,    /* 0xDX    */
  1028.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  1029.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  1030.     _U|_W,        _U|_W,        0,        _W,
  1031.     _L|_W,        _L|_W,        _L|_W,        _L|_W,    /* 0xEX    */
  1032.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  1033.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  1034.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  1035.     0,        _L|_W,        _L|_W,        _L|_W,    /* 0xFX    */
  1036.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  1037.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  1038.     _L|_W,        _L|_W,        0,        0
  1039. };
  1040. SHAR_EOF
  1041. fi # end of overwriting check
  1042. if test -f 'echo.c'
  1043. then
  1044.     echo shar: will not over-write existing file "'echo.c'"
  1045. else
  1046. cat << \SHAR_EOF > 'echo.c'
  1047. /*
  1048.  *        Echo line reading and writing.
  1049.  *
  1050.  * Common routines for reading
  1051.  * and writing characters in the echo line area
  1052.  * of the display screen. Used by the entire
  1053.  * known universe.
  1054.  */
  1055. #include    "def.h"
  1056. #ifdef    VARARGS
  1057. #  include    <varargs.h>
  1058.     static veread();
  1059. #endif
  1060. static eformat();
  1061.  
  1062. int    epresf    = FALSE;        /* Stuff in echo line flag.    */
  1063. /*
  1064.  * Erase the echo line.
  1065.  */
  1066. eerase() {
  1067.     ttcolor(CTEXT);
  1068.     ttmove(nrow-1, 0);
  1069.     tteeol();
  1070.     ttflush();
  1071.     epresf = FALSE;
  1072. }
  1073.  
  1074. /*
  1075.  * Ask "yes" or "no" question.
  1076.  * Return ABORT if the user answers the question
  1077.  * with the abort ("^G") character. Return FALSE
  1078.  * for "no" and TRUE for "yes". No formatting
  1079.  * services are available. No newline required.
  1080.  */
  1081. eyorn(sp) char *sp; {
  1082.     register KEY    s;
  1083.  
  1084.     if (kbdmop == NULL) ewprintf("%s? (y or n) ", sp);
  1085.     for (;;) {
  1086.         s = getkey(0);
  1087.         if (s == 'y' || s == 'Y') return (TRUE);
  1088.         if (s == 'n' || s == 'N') return (FALSE);
  1089.         if (s == (KCTRL|'G') || s == (KCTLX|KCTRL|'G')
  1090.         ||  s == (KMETA|KCTRL|'G')) {
  1091.             (VOID) ctrlg(FALSE, 1, KRANDOM);
  1092.             return ABORT;
  1093.         }
  1094.         if (kbdmop == NULL)
  1095.             ewprintf("Please answer y or n.  %s? (y or n) ", sp);
  1096.     }
  1097. }
  1098.  
  1099. /*
  1100.  * Like eyorn, but for more important question. User must type either all of
  1101.  * "yes" or "no", and the trainling newline.
  1102.  */
  1103. eyesno(sp) char *sp; {
  1104.     register int    s;
  1105.     char        buf[64];
  1106.  
  1107.     s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
  1108.     for (;;) {
  1109.         if (s == ABORT) return ABORT;
  1110.         if (s != FALSE) {
  1111.             if ((buf[0] == 'y' || buf[0] == 'Y')
  1112.             &&  (buf[1] == 'e' || buf[1] == 'E')
  1113.             &&  (buf[2] == 's' || buf[2] == 'S')) return TRUE;
  1114.             if ((buf[0] == 'n' || buf[0] == 'N')
  1115.             &&  (buf[1] == 'o' || buf[0] == 'O')) return FALSE;
  1116.         }
  1117.         s = ereply("Please answer yes or no.  %s? (yes or no) ",
  1118.                buf, sizeof(buf), sp);
  1119.     }
  1120. }
  1121. /*
  1122.  * Write out a prompt, and read back a
  1123.  * reply. The prompt is now written out with full "ewprintf"
  1124.  * formatting, although the arguments are in a rather strange
  1125.  * place. This is always a new message, there is no auto
  1126.  * completion, and the return is echoed as such.
  1127.  */
  1128. #ifdef    VARARGS
  1129. ereply(va_alist)
  1130. va_dcl
  1131. {
  1132.     register int i;
  1133.     va_list pvar;
  1134.     register char *fp, *buf;
  1135.     register int nbuf;
  1136.     
  1137.     va_start(pvar);
  1138.     fp = va_arg(pvar, char *);
  1139.     buf = va_arg(pvar, char *);
  1140.     nbuf = va_arg(pvar, int);
  1141.     i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar);
  1142.     va_end(pvar);
  1143.     return i;
  1144. }
  1145. #else
  1146. /* VARARGS3 */
  1147. ereply(fp, buf, nbuf, arg) char *fp, *buf; int nbuf; long arg; {
  1148.     return (eread(fp, buf, nbuf, EFNEW|EFCR, (char *)&arg));
  1149. }
  1150. #endif
  1151.  
  1152. /*
  1153.  * This is the general "read input from the
  1154.  * echo line" routine. The basic idea is that the prompt
  1155.  * string "prompt" is written to the echo line, and a one
  1156.  * line reply is read back into the supplied "buf" (with
  1157.  * maximum length "len"). The "flag" contains EFNEW (a
  1158.  * new prompt), an EFFUNC (autocomplete), or EFCR (echo
  1159.  * the carriage return as CR).
  1160.  */
  1161. /* VARARGS4 */
  1162. #ifdef    VARARGS
  1163. eread(va_alist)
  1164. va_dcl
  1165. {
  1166.     va_list pvar;
  1167.     char *fp, *buf;
  1168.     int nbuf, flag, i;
  1169.     va_start(pvar);
  1170.     fp   = va_arg(pvar, char *);
  1171.     buf  = va_arg(pvar, char *);
  1172.     nbuf = va_arg(pvar, int);
  1173.     flag = va_arg(pvar, int);
  1174.     i = veread(fp, buf, nbuf, flag, &pvar);
  1175.     va_end(pvar);
  1176.     return i;
  1177. }
  1178. #endif
  1179.  
  1180. #ifdef    VARARGS
  1181. static veread(fp, buf, nbuf, flag, ap) char *fp; char *buf; va_list *ap; {
  1182. #else
  1183. eread(fp, buf, nbuf, flag, ap) char *fp; char *buf; char *ap; {
  1184. #endif
  1185.     register int    cpos;
  1186.     register int    i;
  1187.     register KEY    c;
  1188.  
  1189.     cpos = 0;
  1190.     if (kbdmop != NULL) {            /* In a macro.        */
  1191.         while ((c = *kbdmop++) != '\0')
  1192.             buf[cpos++] = (char) c;
  1193.         buf[cpos] = '\0';
  1194.         goto done;
  1195.     }
  1196.     if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
  1197.         ttcolor(CTEXT);
  1198.         ttmove(nrow-1, 0);
  1199.         epresf = TRUE;
  1200.     } else
  1201.         eputc(' ');
  1202.     eformat(fp, ap);
  1203.     tteeol();
  1204.     ttflush();
  1205.     for (;;) {
  1206.         c = getkey(KQUOTE|KNOMAC);
  1207.         if ((flag&EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
  1208.             cpos += complete(flag, c, buf, cpos);
  1209.             continue;
  1210.         }
  1211.         switch (c) {
  1212.         case 0x0D:            /* Return, done.    */
  1213.             if ((flag&EFFUNC) != 0) {
  1214.                 if ((i = complete(flag, c, buf, cpos)) == 0)
  1215.                     continue;
  1216.                 if (i > 0) cpos += i;
  1217.             }
  1218.             buf[cpos] = '\0';
  1219.             if ((flag&EFCR) != 0) {
  1220.                 ttputc(0x0D);
  1221.                 ttflush();
  1222.             }
  1223.             if (kbdmip != NULL) {
  1224.                 if (kbdmip+cpos+1 > &kbdm[NKBDM-3]) {
  1225.                     ewprintf("Keyboard macro overflow");
  1226.                     ttflush();
  1227.                     return FALSE;
  1228.                 }
  1229.                 for (i = 0; i <= cpos; ++i)
  1230.                     *kbdmip++ = (KEY) buf[i];
  1231.             }
  1232.             goto done;
  1233.  
  1234.         case CCHR('G'):            /* Bell, abort.        */
  1235.             eputc(CCHR('G'));
  1236.             (VOID) ctrlg(FALSE, 0, KRANDOM);
  1237.             ttflush();
  1238.             return (ABORT);
  1239.  
  1240.         case 0x7F:            /* Rubout, erase.    */
  1241.             if (cpos != 0) {
  1242.                 ttputc('\b');
  1243.                 ttputc(' ');
  1244.                 ttputc('\b');
  1245.                 --ttcol;
  1246.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  1247.                     ttputc('\b');
  1248.                     ttputc(' ');
  1249.                     ttputc('\b');
  1250.                     --ttcol;
  1251.                 }
  1252.                 ttflush();
  1253.             }
  1254.             break;
  1255.  
  1256.         case CCHR('X'):            /* C-X            */
  1257.         case CCHR('U'):            /* C-U, kill line.    */
  1258.             while (cpos != 0) {
  1259.                 ttputc('\b');
  1260.                 ttputc(' ');
  1261.                 ttputc('\b');
  1262.                 --ttcol;
  1263.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  1264.                     ttputc('\b');
  1265.                     ttputc(' ');
  1266.                     ttputc('\b');
  1267.                     --ttcol;
  1268.                 }
  1269.             }
  1270.             ttflush();
  1271.             break;
  1272.  
  1273.         case CCHR('Q'):            /* C-Q, quote next    */
  1274.             c = getkey(KQUOTE|KNOMAC) ;
  1275.         default:            /* All the rest.    */
  1276.             if (cpos < nbuf-1) {
  1277.                 buf[cpos++] = (char) c;
  1278.                 eputc((char) c);
  1279.                 ttflush();
  1280.             }
  1281.         }
  1282.     }
  1283. done:
  1284.     if (buf[0] == '\0')
  1285.         return (FALSE);
  1286.     return (TRUE);
  1287. }
  1288.  
  1289. /*
  1290.  * do completion on a list of objects.
  1291.  */
  1292. complete(flags, c, buf, cpos) register char *buf; register int cpos; {
  1293.     register LIST    *lh, *lh2;
  1294. #ifndef    MANX
  1295.     register    /* too many registers mess Manx up */
  1296. #endif
  1297.     int        i, nxtra;
  1298.     int        nhits, bxtra;
  1299.     int        wflag = FALSE;
  1300.     int        msglen, nshown;
  1301.     char        *msg;
  1302.  
  1303.     if ((flags&EFFUNC) != 0) lh = &(symbol[0]->s_list);
  1304.     else if ((flags&EFBUF) != 0) lh = &(bheadp->b_list);
  1305.     else panic("broken complete call: flags");
  1306.  
  1307.     if (c == ' ') wflag = TRUE;
  1308.     else if (c != '\t' && c != 0x0D) panic("broken complete call: c");
  1309.  
  1310.     nhits = 0;
  1311.     nxtra = HUGE;
  1312.  
  1313.     while (lh != NULL) {
  1314.         for (i=0; i<cpos; ++i) {
  1315.             if (buf[i] != lh->l_name[i])
  1316.                 break;
  1317.         }
  1318.         if (i == cpos) {
  1319.             if (nhits == 0)
  1320.                 lh2 = lh;
  1321.             ++nhits;
  1322.             if (lh->l_name[i] == '\0') nxtra = -1;
  1323.             else {
  1324.                 bxtra = getxtra(lh, lh2, cpos, wflag);
  1325.                 if (bxtra < nxtra) nxtra = bxtra;
  1326.                 lh2 = lh;
  1327.             }
  1328.         }
  1329.         lh = lh->l_next;
  1330.     }
  1331.     if (nhits == 0)
  1332.         msg = " [No match]";
  1333.     else if (nhits > 1 && nxtra == 0)
  1334.         msg = " [Ambiguous]";
  1335.     else {        /* Got a match, do it to it */
  1336.         /*
  1337.          * Being lazy - ought to check length, but all things
  1338.          * autocompleted have known types/lengths.
  1339.          */ 
  1340.         if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1;
  1341.         for (i = 0; i < nxtra; ++i) {
  1342.             buf[cpos] = lh2->l_name[cpos];
  1343.             eputc(buf[cpos++]);
  1344.         }
  1345.         ttflush();
  1346.         if (nxtra < 0 && c != 0x0D) return 0;
  1347.         return nxtra;
  1348.     }
  1349.         /* Set up backspaces, etc., being mindful of echo line limit */
  1350.     msglen = strlen(msg);
  1351.     nshown = (ttcol + msglen + 2 > ncol) ? 
  1352.             ncol - ttcol - 2 : msglen;
  1353.     eputs(msg);
  1354.     ttcol -= (i = nshown);        /* update ttcol!        */
  1355.     while (i--)            /* move back before msg        */
  1356.         ttputc('\b');
  1357.     ttflush();            /* display to user        */
  1358.     i = nshown;
  1359.     while (i--)            /* blank out    on next flush    */
  1360.         eputc(' ');
  1361.     ttcol -= (i = nshown);        /* update ttcol on BS's        */
  1362.     while (i--)
  1363.         ttputc('\b');        /* update ttcol again!        */
  1364.     return 0;
  1365.  
  1366. }
  1367.  
  1368. /*
  1369.  * The "lp1" and "lp2" point to list structures. The
  1370.  * "cpos" is a horizontal position in the name.
  1371.  * Return the longest block of characters that can be
  1372.  * autocompleted at this point. Sometimes the two
  1373.  * symbols are the same, but this is normal.
  1374.   */
  1375. getxtra(lp1, lp2, cpos, wflag) register LIST *lp1, *lp2; register int wflag; {
  1376.     register int    i;
  1377.  
  1378.     i = cpos;
  1379.     for (;;) {
  1380.         if (lp1->l_name[i] != lp2->l_name[i]) break;
  1381.         if (lp1->l_name[i] == '\0') break;
  1382.         ++i;
  1383.         if (wflag && !ISWORD(lp1->l_name[i-1])) break;
  1384.     }
  1385.     return (i - cpos);
  1386. }
  1387.  
  1388. /*
  1389.  * Special "printf" for the echo line.
  1390.  * Each call to "ewprintf" starts a new line in the
  1391.  * echo area, and ends with an erase to end of the
  1392.  * echo line. The formatting is done by a call
  1393.  * to the standard formatting routine.
  1394.  */
  1395. #ifdef    VARARGS
  1396. ewprintf(va_alist)
  1397. va_dcl
  1398. {
  1399.     va_list pvar;
  1400.     register char *fp;
  1401.  
  1402.     va_start(pvar);
  1403.     fp = va_arg(pvar, char *);
  1404. #else
  1405. /* VARARGS1 */
  1406. ewprintf(fp, arg) char *fp; {
  1407. #endif
  1408.     ttcolor(CTEXT);
  1409.     ttmove(nrow-1, 0);
  1410. #ifdef    VARARGS
  1411.     eformat(fp, &pvar);
  1412.     va_end(pvar);
  1413. #else
  1414.     eformat(fp, (char *)&arg);
  1415. #endif
  1416.     tteeol();
  1417.     ttflush();
  1418.     epresf = TRUE;
  1419. }
  1420.  
  1421. /*
  1422.  * Printf style formatting. This is
  1423.  * called by both "ewprintf" and "ereply" to provide
  1424.  * formatting services to their clients. The move to the
  1425.  * start of the echo line, and the erase to the end of
  1426.  * the echo line, is done by the caller.
  1427.  * Note: %c works, and prints the "name" of the key. However
  1428.  * the key must be cast to an int to avoid tripping over
  1429.  * various oddities in C argument passing.
  1430.  */
  1431. static eformat(fp, ap) register char *fp;
  1432. #ifdef VARARGS
  1433. register va_list *ap;
  1434. #else
  1435. register char *ap;
  1436. #endif
  1437. {
  1438.     register int    c;
  1439.     char        kname[NKNAME];
  1440.  
  1441.     while ((c = *fp++) != '\0') {
  1442.         if (c != '%')
  1443.             eputc(c);
  1444.         else {
  1445.             c = *fp++;
  1446.             switch (c) {
  1447.             case 'c':
  1448. #ifdef    VARARGS
  1449.                 keyname(kname, va_arg(*ap, int));
  1450. #else
  1451.                 /*NOSTRICT*/
  1452.                 keyname(kname, *(int *)ap);
  1453.                 ap += sizeof(int);
  1454. #endif
  1455.                 eputs(kname);
  1456.                 break;
  1457.  
  1458.             case 'd':
  1459. #ifdef    VARARGS
  1460.                 eputi(va_arg(*ap, int), 10);
  1461. #else
  1462.                 /*NOSTRICT*/
  1463.                 eputi(*(int *)ap, 10);
  1464.                 ap += sizeof(int);
  1465. #endif
  1466.                 break;
  1467.  
  1468.             case 'o':
  1469. #ifdef    VARARGS
  1470.                 eputi(va_arg(*ap, int), 8);
  1471. #else
  1472.                 /*NOSTRICT*/
  1473.                 eputi(*(int *)ap,  8);
  1474.                 ap += sizeof(int);
  1475. #endif
  1476.                 break;
  1477.  
  1478.             case 's':
  1479. #ifdef    VARARGS
  1480.                 eputs(va_arg(*ap, char *));
  1481. #else
  1482.                 /*NOSTRICT*/
  1483.                 eputs(*(char **)ap);
  1484.                 ap += sizeof(char *);
  1485. #endif
  1486.                 break;
  1487.             case 'l':/* explicit longword */
  1488.                 c = *fp++;
  1489.                 switch(c) {
  1490.                 case 'd':
  1491. #ifdef    VARARGS
  1492.                     eputl((long)va_arg(*ap, long), 10L);
  1493. #else
  1494.                     /*NOSTRICT*/
  1495.                     eputl(*(long *)ap, 10L);
  1496.                     ap += sizeof(long);
  1497. #endif
  1498.                     break;
  1499.                 default:
  1500.                     eputc(c);
  1501.                     break;
  1502.                 }
  1503.                 break;
  1504.  
  1505.             default:
  1506.                 eputc(c);
  1507.             }
  1508.         }
  1509.     }
  1510. }
  1511.  
  1512. /*
  1513.  * Put integer, in radix "r".
  1514.  */
  1515. static eputi(i, r) register int i; register int r; {
  1516.     register int    q;
  1517.  
  1518.     if ((q=i/r) != 0)
  1519.         eputi(q, r);
  1520.     eputc(i%r+'0');
  1521. }
  1522.  
  1523. /*
  1524.  * Put long, in radix "r".
  1525.  */
  1526. static eputl(l, r) register long l; register long r; {
  1527.     register long    q;
  1528.  
  1529.     if ((q=l/r) != 0)
  1530.         eputl(q, r);
  1531.     eputc((int)(l%r)+'0');
  1532. }
  1533.  
  1534. /*
  1535.  * Put string.
  1536.  */
  1537. eputs(s) register char *s; {
  1538.     register int    c;
  1539.  
  1540.     while ((c = *s++) != '\0')
  1541.         eputc(c);
  1542. }
  1543.  
  1544. /*
  1545.  * Put character. Watch for
  1546.  * control characters, and for the line
  1547.  * getting too long.
  1548.  */
  1549. static eputc(c) register char c; {
  1550.     if (ttcol+2 < ncol) {
  1551.         if (ISCTRL(c) != FALSE) {
  1552.             eputc('^');
  1553.             c ^= 0x40;
  1554.         }
  1555.         ttputc(c);
  1556.         ++ttcol;
  1557.     }
  1558. }
  1559.  
  1560. SHAR_EOF
  1561. fi # end of overwriting check
  1562. if test -f 'extend.c'
  1563. then
  1564.     echo shar: will not over-write existing file "'extend.c'"
  1565. else
  1566. cat << \SHAR_EOF > 'extend.c'
  1567. /*
  1568.  *        Extended (M-X) commands.
  1569.  */
  1570. #include    "def.h"
  1571.  
  1572. /*
  1573.  * This function modifies the keyboard
  1574.  * binding table, by adjusting the entries in the
  1575.  * big "bindings" array. Most of the grief deals with the
  1576.  * prompting for additional arguments.
  1577.  */
  1578. /*ARGSUSED*/
  1579. bindtokey(f, n, k) {
  1580.     register int    s;
  1581.     register SYMBOL    *sp;
  1582.     int        c;
  1583.     char        xname[NXNAME];
  1584.  
  1585.     if (kbdmop == NULL)
  1586.         ewprintf("Set key globally: ") ;
  1587.     c = (int) getkey(0);
  1588.     if ((s=eread("Set key %c to command: ", xname, NXNAME, EFNEW|EFFUNC,
  1589. #ifdef VARARGS
  1590.              c
  1591. #else
  1592.              (char *) &c, (char *) NULL
  1593. #endif
  1594.              )) != TRUE)
  1595.         return (s);
  1596.     if ((sp=symlookup(xname)) == NULL) {
  1597.         ewprintf("[No match]");
  1598.         return (FALSE);
  1599.     }
  1600.     binding[(KEY) c] = sp;            /* rebind new.        */
  1601.     return (TRUE);
  1602. }
  1603.  
  1604. /*
  1605.  * User function to unbind keys. Just call the unbind we already have. 
  1606.  */
  1607. /*ARGSUSED*/
  1608. unsetkey(f, n, k) {
  1609.     register KEY    key;
  1610.     
  1611.     if (kbdmop == NULL) ewprintf("Unset key globally: ") ;
  1612.     key = getkey(0);
  1613.     if (key == (KCTRL|'G') || key == (KCTLX|KCTRL|'G')
  1614.     || key == (KMETA|KCTRL|'G')) {
  1615.         (VOID) ctrlg(FALSE, 1, KRANDOM);
  1616.         return ABORT;
  1617.     }
  1618.     binding[key] = NULL;
  1619.     return TRUE;
  1620. }
  1621.  
  1622. /*
  1623.  * Extended command. Call the message line
  1624.  * routine to read in the command name and apply autocompletion
  1625.  * to it. When it comes back, look the name up in the symbol table
  1626.  * and run the command if it is found and has the right type.
  1627.  * Print an error if there is anything wrong.
  1628.  */
  1629. /*ARGSUSED*/
  1630. extend(f, n, k) {
  1631.     register SYMBOL    *sp;
  1632.     register int    s;
  1633.     char        xname[NXNAME];
  1634.  
  1635.     if (f == FALSE)
  1636.         s = eread("M-x ", xname, NXNAME, EFNEW|EFFUNC
  1637. #ifndef VARARGS
  1638.              , (char *) NULL
  1639. #endif
  1640.              ) ;
  1641.     else
  1642.         s = eread("%d M-x ", xname, NXNAME, EFNEW|EFFUNC, 
  1643. #ifdef    VARARGS
  1644.              n
  1645. #else
  1646.              (char *) &n, (char *) NULL
  1647. #endif
  1648.              ) ;
  1649.     if (s != TRUE) return (s);
  1650.     if ((sp=symlookup(xname)) != NULL)
  1651.         return ((*sp->s_funcp)(f, n, KRANDOM));
  1652.     ewprintf("[No match]");
  1653.     return FALSE;
  1654. }
  1655.  
  1656. /*
  1657.  * Read a key from the keyboard, and look it
  1658.  * up in the binding table. Display the name of the function
  1659.  * currently bound to the key. Say that the key is not bound
  1660.  * if it is indeed not bound, or if the type is not a
  1661.  * "builtin". This is a bit of overkill, because this is the
  1662.  * only kind of function there is.
  1663.  */
  1664. /*ARGSUSED*/
  1665. desckey(f, n, k) {
  1666.     register SYMBOL    *sp;
  1667.     register KEY    c;
  1668.  
  1669.     if (kbdmop == NULL) ewprintf("Describe key briefly: ");
  1670.     c = getkey(0);
  1671.     if (kbdmop != NULL) return TRUE;
  1672.     if ((sp=binding[c]) == NULL)
  1673.         ewprintf("%c is undefined", (int) c);
  1674.     else
  1675.         ewprintf("%c runs the command %s", (int) c, sp->s_name);
  1676.     return (TRUE);
  1677. }
  1678.  
  1679. /*
  1680.  * This function creates a table, listing all
  1681.  * of the command keys and their current bindings, and stores
  1682.  * the table in the standard pop-op buffer (the one used by the
  1683.  * directory list command, the buffer list command, etc.). This
  1684.  * lets MicroEMACS produce it's own wall chart. The bindings to
  1685.  * "ins-self" are only displayed if there is an argument.
  1686.  */
  1687. /*ARGSUSED*/
  1688. wallchart(f, n, k) {
  1689.     register int    key;
  1690.     register SYMBOL    *sp;
  1691.     register char    *cp1;
  1692.     register char    *cp2;
  1693.     BUFFER        *bp;
  1694.     char        buf[64];
  1695.  
  1696.     bp = bfind("*Help*", TRUE);
  1697.     if (bclear(bp) != TRUE)            /* Clear it out.    */
  1698.         return TRUE;
  1699.     for (key=0; key<NKEYS; ++key) {        /* For all keys.    */
  1700.         sp = binding[key];
  1701.         if (sp != NULL
  1702.         && (f!=FALSE
  1703.         || strcmp(sp->s_name, "self-insert-command")!=0)) {
  1704.             keyname(buf, key);
  1705.             cp1 = &buf[0];        /* Find end.        */
  1706.             while (*cp1 != 0)
  1707.                 ++cp1;
  1708.             while (cp1 < &buf[32])    /* Goto column 32.    */
  1709.                 *cp1++ = ' ';                
  1710.             cp2 = sp->s_name;    /* Add function name.    */
  1711.             while (*cp1++ = *cp2++)
  1712.                 ;
  1713.             if (addline(bp, buf) == FALSE)
  1714.                 return (FALSE);
  1715.         }
  1716.     }
  1717.     return popbuf(bp) == NULL ? FALSE : TRUE;
  1718. }
  1719.  
  1720. #ifdef    STARTUP
  1721. /*
  1722.  * Define the commands needed to do startup-file processing.
  1723.  * This code is mostly a kludge just so we can get startup-file processing.
  1724.  *
  1725.  * If you're serious about having this code, you should rewrite it.
  1726.  * To wit: 
  1727.  *    It has lots of funny things in it to make the startup-file look
  1728.  *    like a GNU startup file; mostly dealing with parens and semicolons.
  1729.  *    This should all vanish.
  1730.  *
  1731.  *    It uses the same buffer as keyboard macros. The fix is easy (make
  1732.  *    a new function "execmacro" that takes a pointer to char and
  1733.  *    does what ctlxe does on it. Make ctlxe and excline both call it.)
  1734.  *    but would slow down the non-micro version.
  1735.  *
  1736.  * We define eval-expression because it's easy. It's pretty useless,
  1737.  * since it duplicates the functionality of execute-extended-command.
  1738.  * All of this is just to support startup files, and should be turned
  1739.  * off for micros.
  1740.  */
  1741.  
  1742. /*
  1743.  * evalexpr - get one line from the user, and run it. Identical in function
  1744.  *    to extend, but easy.
  1745.  */
  1746. /*ARGSUSED*/
  1747. evalexpr(f, n, k) {
  1748.     register int    s;
  1749.     char        exbuf[NKBDM];
  1750.  
  1751.     if ((s = ereply("Eval: ", exbuf, NKBDM)) != TRUE)
  1752.         return s;
  1753.     return excline(exbuf);
  1754. }
  1755. /*
  1756.  * evalbuffer - evaluate the current buffer as line commands. Useful
  1757.  *    for testing startup files.
  1758.  */
  1759. /*ARGSUSED*/
  1760. evalbuffer(f, n, k) {
  1761.     register LINE    *lp;
  1762.     register BUFFER    *bp = curbp;
  1763.     register int    s;
  1764.     static char    excbuf[NKBDM];
  1765.     char        *strncpy();
  1766.  
  1767.     for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
  1768.         if (llength(lp) >= NKBDM + 1) return FALSE ;
  1769.         (VOID) strncpy(excbuf, ltext(lp), NKBDM);
  1770.         if ((s = excline(excbuf)) != TRUE) return s;
  1771.     }
  1772.     return TRUE;
  1773. }
  1774. /*
  1775.  * evalfile - go get a file and evaluate it as line commands. You can
  1776.  *    go get your own startup file if need be.
  1777.  */
  1778. /*ARGSUSED*/
  1779. evalfile(f, n, k) {
  1780.     register int    s;
  1781.     char        fname[NFILEN];
  1782.  
  1783.     if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
  1784.         return s;
  1785.     return load(fname);
  1786. }
  1787.  
  1788. /*
  1789.  * load - go load the file name we got passed.
  1790.  */
  1791. load(fname) char *fname; {
  1792.     register int    s;
  1793.     char        excbuf[NKBDM];
  1794.  
  1795.     if (ffropen(fname) == FIOERR)
  1796.         return FALSE;
  1797.     while ((s = ffgetline(excbuf, NKBDM)) == FIOSUC)
  1798.         if (excline(excbuf) != TRUE) break;
  1799.     (VOID) ffclose();
  1800.     return s == FIOEOF;
  1801. }
  1802.  
  1803. /*
  1804.  * excline - run a line from a load file or eval-expression.
  1805.  */
  1806. excline(line) register char *line; {
  1807.     register char    *funcp, *argp = NULL;
  1808.     char        *skipwhite(), *parsetoken(), *backquote();
  1809.     int        status;
  1810.  
  1811.     /* Don't know if it works; don't care - mwm */
  1812.     if (kbdmip != NULL || kbdmop != NULL) {
  1813.         ewprintf("Not now!") ;
  1814.         return FALSE;
  1815.     }
  1816.  
  1817.     funcp = skipwhite(line);
  1818.     if (*funcp == '\0') return TRUE;    /* No error on blank lines */
  1819.     line = parsetoken(funcp);
  1820.     if (*line != '\0') {
  1821.         *line++ = '\0';
  1822.         line = skipwhite(line);
  1823.         if ((*line >= '0' && *line <= '9') || *line == '-') {
  1824.             argp = line;
  1825.             line = parsetoken(line);
  1826.         }
  1827.     }
  1828.  
  1829.     kbdmip = &kbdm[0];
  1830.     if (argp != NULL) {
  1831.         *kbdmip++ = (KEY) (KCTRL|'U');
  1832.         *kbdmip++ = (KEY) atoi(argp);
  1833.     }
  1834.     *kbdmip++ = (KEY) (KMETA|'X');
  1835.     /* Pack in function */
  1836.     while (*funcp != '\0')
  1837.         if (kbdmip+1 <= &kbdm[NKBDM-3]) *kbdmip++ = (KEY) *funcp++;
  1838.         else {
  1839.             ewprintf("eval-expression macro overflow");
  1840.             ttflush();
  1841.             return FALSE;
  1842.         }
  1843.     *kbdmip++ = '\0';    /* done with function */
  1844.     /* Pack away all the args now...    */
  1845.     while (*line != '\0') {
  1846.         argp = skipwhite(line);
  1847.         if (*argp == '\0') break ;
  1848.         line = parsetoken(argp) ;
  1849.         /* Slightly bogus for strings. But they should be SHORT! */
  1850.         if (kbdmip+(line-argp)+1 > &kbdm[NKBDM-3]) {
  1851.             ewprintf("eval-expression macro overflow");
  1852.             ttflush();
  1853.             return FALSE;
  1854.         }
  1855.         if (*line != '\0') *line++ = '\0';
  1856.         if (*argp != '"') {
  1857.             if (*argp == '\'') ++argp;
  1858.             while (*argp != '\0')
  1859.                 *kbdmip++ = (KEY) *argp++;
  1860.             *kbdmip++ = '\0';
  1861.         }
  1862.         else {    /* Quoted strings special again */
  1863.             ++argp;
  1864.             while (*argp != '"' && *argp != '\0')
  1865.                 if (*argp != '\\') *kbdmip++ = (KEY) *argp++;
  1866.                 else argp = backquote(++argp, TRUE);
  1867.             /* Quotes strings are gotkey'ed, so no trailing null */
  1868.         }
  1869.     }
  1870.     *kbdmip++ = (KEY) (KCTLX|')');
  1871.     *kbdmip++ = '\0';
  1872.     kbdmip = NULL;
  1873.     status = ctlxe(FALSE, 1, KRANDOM);
  1874.     kbdm[0] = (KCTLX|')');
  1875.     return status;
  1876. }
  1877. /*
  1878.  * a pair of utility functions for the above
  1879.  */
  1880. char *
  1881. skipwhite(s) register char *s; {
  1882.  
  1883.     while ((*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
  1884.         && *s != '\0')
  1885.         if (*s == ';') *s = '\0' ;
  1886.         else s++;
  1887.     return s;
  1888. }
  1889.  
  1890. char *
  1891. parsetoken(s) register char *s; {
  1892.  
  1893.     if (*s != '"')
  1894.         while (*s != ' ' && *s != '\t' && *s != '(' && *s != ')'
  1895.             && *s != '\0') {
  1896.             if (*s == ';') *s = '\0';
  1897.             else s++;
  1898.         }
  1899.     else    /* Strings get special treatment */
  1900.         do {
  1901.             /* Beware: You can \ out the end of the string! */
  1902.             if (*s == '\\') ++s;
  1903.             if (ISLOWER(*s)) *s = TOUPPER(*s);
  1904.             } while (*++s != '"' && *s != '\0');
  1905.     return s;
  1906. }
  1907. /*
  1908.  * Put a backquoted string element into the keyboard macro. Return pointer
  1909.  * to char following backquoted stuff.
  1910.  */
  1911. char *
  1912. backquote(in, flag) char *in; {
  1913.     switch (*in++) {
  1914.         case 'T': *kbdmip++ = (KEY) (KCTRL|'I');
  1915.               break;
  1916.         case 'N': *kbdmip++ = (KEY) (KCTRL|'J');
  1917.               break; 
  1918.         case 'R': *kbdmip++ = (KEY) (KCTRL|'M');
  1919.               break;
  1920.         case '^': *kbdmip = (KEY) (KCTRL|*in++);
  1921.               if (flag != FALSE && *kbdmip == (KEY) (KCTRL|'X')) {
  1922.                   if (*in == '\\') in = backquote(++in, FALSE);
  1923.                   else *kbdmip++ = (KEY) *in++;
  1924.                   kbdmip[-1] |= (KEY) KCTLX;
  1925.               } else ++kbdmip;
  1926.               break;
  1927.         case 'E':
  1928.               if (flag != TRUE) *kbdmip++ = (KEY) (KCTRL|'[');
  1929.               else if (*in != '\\') *kbdmip++ = (KEY) (KMETA|*in++);
  1930.               else {
  1931.                   in = backquote(++in, FALSE);
  1932.                   kbdmip[-1] |= (KEY) KMETA;
  1933.               }
  1934.               break;
  1935.     }
  1936.     return in;
  1937. }
  1938. #endif    STARTUP
  1939. SHAR_EOF
  1940. fi # end of overwriting check
  1941. if test -f 'file.c'
  1942. then
  1943.     echo shar: will not over-write existing file "'file.c'"
  1944. else
  1945. cat << \SHAR_EOF > 'file.c'
  1946. /*
  1947.  *         File commands.
  1948.  */
  1949. #include    "def.h"
  1950.  
  1951. BUFFER    *findbuffer();
  1952.  
  1953. /*
  1954.  * insert a file into the current buffer. Real easy - just call the
  1955.  * insertfile routine with the file name.
  1956.  */
  1957. /*ARGSUSED*/
  1958. fileinsert(f, n, k) {
  1959.     register int    s;
  1960.     char        fname[NFILEN];
  1961.  
  1962.     if ((s=ereply("Insert file: ", fname, NFILEN)) != TRUE)
  1963.         return (s);
  1964.     adjustcase(fname);
  1965.     return (insertfile(fname, (char *) NULL)); /* don't set buffer name */
  1966. }
  1967.  
  1968. /*
  1969.  * Select a file for editing.
  1970.  * Look around to see if you can find the
  1971.  * fine in another buffer; if you can find it
  1972.  * just switch to the buffer. If you cannot find
  1973.  * the file, create a new buffer, read in the
  1974.  * text, and switch to the new buffer.
  1975.  */
  1976. /*ARGSUSED*/
  1977. filevisit(f, n, k) {
  1978.     register BUFFER    *bp;
  1979.     int        s;
  1980.     char        fname[NFILEN];
  1981.  
  1982.     if ((s=ereply("Find file: ", fname, NFILEN)) != TRUE)
  1983.         return (s);
  1984.     if ((bp = findbuffer(fname, &s)) == NULL) return s;
  1985.     curbp = bp;
  1986.     if (showbuffer(bp, curwp, WFHARD) != TRUE) return FALSE;
  1987.     if (bp->b_fname[0] == 0)
  1988.         return (readin(fname));        /* Read it in.        */
  1989.     return TRUE;
  1990. }
  1991.  
  1992. /*
  1993.  * Pop to a file in the other window. Same as last function, just
  1994.  * popbuf instead of showbuffer.
  1995.  */
  1996. /*ARGSUSED*/
  1997. poptofile(f, n, k) {
  1998.     register BUFFER    *bp;
  1999.     register WINDOW    *wp;
  2000.     int        s;
  2001.     char        fname[NFILEN];
  2002.  
  2003.     if ((s=ereply("Find file in other window: ", fname, NFILEN)) != TRUE)
  2004.         return (s);
  2005.     if ((bp = findbuffer(fname, &s)) == NULL) return s;
  2006.     if ((wp = popbuf(bp)) == NULL) return FALSE;
  2007.     curbp = bp;
  2008.     curwp = wp;
  2009.     if (bp->b_fname[0] == 0)
  2010.         return (readin(fname));        /* Read it in.        */
  2011.     return TRUE;
  2012. }
  2013.  
  2014. /*
  2015.  * given a file name, either find the buffer it uses, or create a new
  2016.  * empty buffer to put it in.
  2017.  */
  2018. BUFFER *
  2019. findbuffer(fname, s) char *fname; int *s; {
  2020.     register BUFFER    *bp;
  2021.     char        bname[NBUFN];
  2022.  
  2023.     adjustcase(fname);
  2024.     for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
  2025.         if (strcmp(bp->b_fname, fname) == 0) {
  2026.             return bp;
  2027.         }
  2028.     }
  2029.     makename(bname, fname);            /* New buffer name.    */
  2030.     while ((bp=bfind(bname, FALSE)) != NULL) {
  2031.         *s = ereply("Buffer name: ", bname, NBUFN);
  2032.         if (*s == ABORT)        /* ^G to just quit    */
  2033.             return NULL;
  2034.         if (*s == FALSE) {        /* CR to clobber it    */
  2035.             bp->b_fname[0] = '\0';
  2036.             break;
  2037.         }
  2038.     }
  2039.     if (bp == NULL) bp = bfind(bname, TRUE);
  2040.     *s = FALSE;
  2041.     return bp;
  2042. }
  2043.  
  2044. /*
  2045.  * Read the file "fname" into the current buffer.
  2046.  * Make all of the text in the buffer go away, after checking
  2047.  * for unsaved changes. This is called by the "read" command, the
  2048.  * "visit" command, and the mainline (for "uemacs file").
  2049.  */
  2050. readin(fname) char *fname; {
  2051.     register int        status;
  2052.     register WINDOW        *wp;
  2053.  
  2054.     if (bclear(curbp) != TRUE)        /* Might be old.    */
  2055.         return TRUE;
  2056.     status = insertfile(fname, fname) ;
  2057.     curbp->b_flag &= ~BFCHG;        /* No change.        */
  2058.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  2059.         if (wp->w_bufp == curbp) {
  2060.             wp->w_linep = lforw(curbp->b_linep);
  2061.             wp->w_dotp  = lforw(curbp->b_linep);
  2062.             wp->w_doto  = 0;
  2063.             wp->w_markp = NULL;
  2064.             wp->w_marko = 0;
  2065.         }
  2066.     }
  2067.     return status;
  2068. }
  2069. /*
  2070.  * insert a file in the current buffer, after dot. Set mark
  2071.  * at the end of the text inserted, point at the beginning.
  2072.  * Return a standard status. Print a summary (lines read,
  2073.  * error message) out as well. If the
  2074.  * BACKUP conditional is set, then this routine also does the read
  2075.  * end of backup processing. The BFBAK flag, if set in a buffer,
  2076.  * says that a backup should be taken. It is set when a file is
  2077.  * read in, but not on a new file (you don't need to make a backup
  2078.  * copy of nothing).
  2079.  *
  2080.  * Warning: Adds a trainling nl to files that don't end in one!
  2081.  * Need to fix, but later (I suspect that it will require a change
  2082.  * in the fileio files for all systems involved).
  2083.  */
  2084. insertfile(fname, newname) char fname[], newname[]; {
  2085.     register LINE    *lp1;
  2086.     register LINE    *lp2;
  2087.     LINE        *olp;            /* Line we started at */
  2088.     int        opos;            /* and offset into it */
  2089.     register WINDOW    *wp;
  2090.     register int    i;
  2091.     register int    nbytes;
  2092.     int        s, nline;
  2093.     BUFFER        *bp;
  2094.     char        line[NLINE];
  2095.  
  2096.     bp = curbp;                /* Cheap.        */
  2097.     if (newname != (char *) NULL)
  2098.         (VOID) strcpy(bp->b_fname, newname);
  2099.     if ((s=ffropen(fname)) == FIOERR)     /* Hard file open.    */
  2100.         goto out;
  2101.     if (s == FIOFNF) {            /* File not found.    */
  2102.         if (kbdmop == NULL)
  2103.             if (newname != NULL)
  2104.                 ewprintf("(New file)");
  2105.             else    ewprintf("(File not found)");
  2106.         goto out;
  2107.     }
  2108.     opos = curwp->w_doto;
  2109.     /* Open a new line, at point, and start inserting after it */
  2110.     (VOID) lnewline();
  2111.     olp = lback(curwp->w_dotp);
  2112.     nline = 0;            /* Don't count fake line at end */
  2113.     while ((s=ffgetline(line, NLINE)) == FIOSUC) {
  2114.         nbytes = strlen(line);
  2115.         if ((lp1=lalloc((RSIZE) nbytes)) == NULL) {
  2116.             s = FIOERR;        /* Keep message on the    */
  2117.             break;            /* display.        */
  2118.         }
  2119.         lp2 = lback(curwp->w_dotp);
  2120.         lp2->l_fp = lp1;
  2121.         lp1->l_fp = curwp->w_dotp;
  2122.         lp1->l_bp = lp2;
  2123.         curwp->w_dotp->l_bp = lp1;
  2124.         for (i=0; i<nbytes; ++i)
  2125.             lputc(lp1, i, line[i]);
  2126.         ++nline;
  2127.     }
  2128.     (VOID) ffclose();            /* Ignore errors.    */
  2129.     if (s==FIOEOF && kbdmop==NULL) {    /* Don't zap an error.    */
  2130.         if (nline == 1)
  2131.             ewprintf("(Read 1 line)");
  2132.         else
  2133.             ewprintf("(Read %d lines)", nline);
  2134.     }
  2135.     /* Set mark at the end of the text */
  2136.     curwp->w_markp = curwp->w_dotp;
  2137.     curwp->w_marko = curwp->w_doto;
  2138.     /* Now, delete the results of the lnewline we started with */
  2139.     curwp->w_dotp = olp;
  2140.     curwp->w_doto = opos;
  2141.     (VOID) ldelnewline();
  2142.     curwp->w_doto = opos;            /* and dot is right    */
  2143. #ifdef    BACKUP
  2144.     if (newname != NULL)
  2145.         bp->b_flag |= BFCHG | BFBAK;    /* Need a backup.    */
  2146.     else    bp->b_flag |= BFCHG;
  2147. #else
  2148.     bp->b_flag |= BFCHG;
  2149. #endif
  2150.     /* if the insert was at the end of buffer, set lp1 to the end of
  2151.      * buffer line, and lp2 to the beginning of the newly inserted
  2152.      * text.  (Otherwise lp2 is set to NULL.)  This is 
  2153.      * used below to set pointers in other windows correctly if they
  2154.      * are also at the end of buffer.
  2155.      */
  2156.     lp1 = bp->b_linep;
  2157.     if (curwp->w_markp == lp1)
  2158.         lp2 = curwp->w_dotp;
  2159.     else {
  2160. out:        lp2 = NULL;
  2161.     }
  2162.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  2163.         if (wp->w_bufp == curbp) {
  2164.             wp->w_flag |= WFMODE|WFEDIT;
  2165.             if (wp != curwp && lp2 != NULL) {
  2166.                 if (wp->w_dotp == lp1)
  2167.                     wp->w_dotp = lp2;
  2168.                 if (wp->w_markp == lp1)
  2169.                     wp->w_markp = lp2;
  2170.                 if (wp->w_linep == lp1)
  2171.                     wp->w_linep = lp2;
  2172.             }
  2173.         }
  2174.     }
  2175.     if (s == FIOERR)            /* False if error.    */
  2176.         return (FALSE);
  2177.     return (TRUE);
  2178. }
  2179.  
  2180. /*
  2181.  * Take a file name, and from it
  2182.  * fabricate a buffer name. This routine knows
  2183.  * about the syntax of file names on the target system.
  2184.  * BDC1        left scan delimiter.
  2185.  * BDC2        optional second left scan delimiter.
  2186.  * BDC3        optional right scan delimiter.
  2187.  */
  2188. makename(bname, fname) char bname[]; char fname[]; {
  2189.     register char    *cp1;
  2190.     register char    *cp2;
  2191.  
  2192.     cp1 = &fname[0];
  2193.     while (*cp1 != 0)
  2194.         ++cp1;
  2195. #ifdef    BDC2
  2196.     while (cp1!=&fname[0] && cp1[-1]!=BDC1 && cp1[-1]!=BDC2)
  2197.         --cp1;
  2198. #else
  2199.     while (cp1!=&fname[0] && cp1[-1]!=BDC1)
  2200.         --cp1;
  2201. #endif
  2202.     cp2 = &bname[0];
  2203. #ifdef    BDC3
  2204.     while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=BDC3)
  2205.         *cp2++ = *cp1++;
  2206. #else
  2207.     while (cp2!=&bname[NBUFN-1] && *cp1!=0)
  2208.         *cp2++ = *cp1++;
  2209. #endif
  2210.     *cp2 = 0;
  2211. }
  2212.  
  2213. /*
  2214.  * Ask for a file name, and write the
  2215.  * contents of the current buffer to that file.
  2216.  * Update the remembered file name and clear the
  2217.  * buffer changed flag. This handling of file names
  2218.  * is different from the earlier versions, and
  2219.  * is more compatable with Gosling EMACS than
  2220.  * with ITS EMACS.
  2221.  */
  2222. /*ARGSUSED*/
  2223. filewrite(f, n, k) {
  2224.     register int    s;
  2225.     char        fname[NFILEN];
  2226.  
  2227.     if ((s=ereply("Write file: ", fname, NFILEN)) != TRUE)
  2228.         return (s);
  2229.     adjustcase(fname);
  2230.     if ((s=writeout(curbp, fname)) == TRUE) {
  2231.         (VOID) strcpy(curbp->b_fname, fname);
  2232. #ifdef    BACKUP
  2233.         curbp->b_flag &= ~(BFBAK | BFCHG);
  2234. #else
  2235.         curbp->b_flag &= ~BFCHG;
  2236. #endif
  2237.         upmodes(curbp);
  2238.     }
  2239.     return (s);
  2240. }
  2241.  
  2242. /*
  2243.  * Save the contents of the current buffer back into
  2244.  * its associated file. Do nothing if there have been no changes
  2245.  * (is this a bug, or a feature). Error if there is no remembered
  2246.  * file name. If this is the first write since the read or visit,
  2247.  * then a backup copy of the file is made.
  2248.  */
  2249. /*ARGSUSED*/
  2250. filesave(f, n, k) {
  2251.     register int    s;
  2252.  
  2253.     if ((curbp->b_flag&BFCHG) == 0)    {    /* Return, no changes.    */
  2254.         if (kbdmop == NULL) ewprintf("(No changes need to be saved)");
  2255.         return (TRUE);
  2256.     }
  2257.     if (curbp->b_fname[0] == 0) {        /* Must have a name.    */
  2258.         ewprintf("No file name");
  2259.         return (FALSE);
  2260.     }
  2261. #ifdef    BACKUP
  2262.     if ((curbp->b_flag&BFBAK) != 0) {
  2263.         s = fbackupfile(curbp->b_fname);
  2264.         if (s == ABORT)            /* Hard error.        */
  2265.             return FALSE;
  2266.         if (s == FALSE            /* Softer error.    */
  2267.         && (s=eyesno("Backup error, save anyway")) != TRUE)
  2268.             return (s);
  2269.     }
  2270. #endif
  2271.     if ((s=writeout(curbp, curbp->b_fname)) == TRUE) {
  2272. #ifdef    BACKUP
  2273.         curbp->b_flag &= ~(BFCHG | BFBAK);
  2274. #else
  2275.         curbp->b_flag &= ~BFCHG;
  2276. #endif
  2277.         upmodes(curbp);
  2278.     }
  2279.     return (s);
  2280. }
  2281.  
  2282. /*
  2283.  * This function performs the details of file
  2284.  * writing; writing the file in buffer bp to
  2285.  * file fn. Uses the file management routines
  2286.  * in the "fileio.c" package. Most of the grief
  2287.  * is checking of some sort.
  2288.  */
  2289. writeout(bp, fn) register BUFFER *bp; char *fn; {
  2290.     register int    s;
  2291.     register LINE    *lp;
  2292.  
  2293.     if ((s=ffwopen(fn)) != FIOSUC)        /* Open writes message.    */
  2294.         return (FALSE);
  2295.     lp = lforw(bp->b_linep);        /* First line.        */
  2296.     while (lp != bp->b_linep) {
  2297.         if ((s=ffputline(&(ltext(lp))[0], llength(lp))) != FIOSUC)
  2298.             break;
  2299.         lp = lforw(lp);
  2300.     }
  2301.     if (s == FIOSUC) {            /* No write error.    */
  2302.         s = ffclose();
  2303.         if (s==FIOSUC && kbdmop==NULL)
  2304.             ewprintf("Wrote %s", fn);
  2305.     } else                    /* Ignore close error    */
  2306.         (VOID) ffclose();        /* if a write error.    */
  2307.     if (s != FIOSUC)            /* Some sort of error.    */
  2308.         return (FALSE);
  2309.     return (TRUE);
  2310. }
  2311.  
  2312. /*
  2313.  * Tag all windows for bp (all windows if bp NULL) as needing their
  2314.  * mode line updated.
  2315.  */
  2316. upmodes(bp) register BUFFER *bp; {
  2317.     register WINDOW    *wp;
  2318.  
  2319.     for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
  2320.         if (bp == NULL || curwp->w_bufp == bp) wp->w_flag |= WFMODE;
  2321. }
  2322.  
  2323. SHAR_EOF
  2324. fi # end of overwriting check
  2325. if test -f 'match.c'
  2326. then
  2327.     echo shar: will not over-write existing file "'match.c'"
  2328. else
  2329. cat << \SHAR_EOF > 'match.c'
  2330. /*
  2331.  * Name:    MicroEMACS
  2332.  *         Limited parenthesis matching routines
  2333.  * Version:    Gnu30
  2334.  * Last edit:    13-Jul-86
  2335.  * Created:    19-May-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
  2336.  *
  2337.  * The hacks in this file implement automatic matching
  2338.  * of (), [], {}, and other characters.  It would be
  2339.  * better to have a full-blown syntax table, but there's
  2340.  * enough overhead in the editor as it is.
  2341.  *
  2342.  * Since I often edit Scribe code, I've made it possible to
  2343.  * blink arbitrary characters -- just bind delimiter characters
  2344.  * to "blink-matching-paren-hack"
  2345.  */
  2346. #include    "def.h"
  2347.  
  2348. /* Balance table. When balance() encounters a character
  2349.  * that is to be matched, it first searches this table
  2350.  * for a balancing left-side character.  If the character
  2351.  * is not in the table, the character is balanced by itself.
  2352.  * This is to allow delimiters in Scribe documents to be matched.
  2353.  */    
  2354.  
  2355. static struct balance {
  2356.     char left, right;
  2357. } bal[] = {
  2358.     { '(', ')' },
  2359.     { '[', ']' },
  2360.     { '{', '}' },
  2361.     { '<', '>' },
  2362.     { '\0','\0'}
  2363. };
  2364.  
  2365. /*
  2366.  * Fake the GNU "blink-matching-paren" variable.
  2367.  * If the argument exists, nonzero means show,
  2368.  * zero means don't.  If it doesn't exist,
  2369.  * pretend it's nonzero.
  2370.  */
  2371.  
  2372. blinkparen(f, n, k)
  2373. {
  2374.     register char    *command;
  2375.     register SYMBOL    *sp;
  2376.  
  2377.     if (f == FALSE)
  2378.         n = 1;
  2379.     command = (n == 0) ? "self-insert-command" :
  2380.                  "blink-matching-paren-hack";
  2381.     if ((sp=symlookup(command)) == NULL) {
  2382.         ewprintf("blinkparen: no binding for %s",command);
  2383.         return (FALSE);
  2384.     }
  2385.     binding[(KEY) ')'] = sp;        /* rebind paren        */
  2386.     return (TRUE);    
  2387. }
  2388.  
  2389. /*
  2390.  * Self-insert character, then show matching character,
  2391.  * if any.  Bound to "blink-matching-paren-command".
  2392.  */
  2393.  
  2394. showmatch(f, n, k)
  2395. {
  2396.     register int  i, s;
  2397.  
  2398.     if (k == KRANDOM)
  2399.         return(FALSE);
  2400.     for (i = 0; i < n; i++) {
  2401.         if ((s = selfinsert(f, 1, k)) != TRUE)
  2402.             return(s);
  2403.         if (balance(k) != TRUE)    /* unbalanced -- warn user */
  2404.             ttbeep();
  2405.     }
  2406.     return (TRUE);
  2407. }
  2408.  
  2409. /*
  2410.  * Search for and display a matching character.
  2411.  *
  2412.  * This routine does the real work of searching backward
  2413.  * for a balancing character.  If such a balancing character
  2414.  * is found, it uses displaymatch() to display the match.
  2415.  */
  2416.  
  2417. static balance(k)
  2418. int k;
  2419. {
  2420.     register LINE    *clp;
  2421.     register int    cbo;
  2422.     int    c;
  2423.     int    i;
  2424.     int    rbal, lbal;
  2425.     int    depth;
  2426.  
  2427.     rbal = k & KCHAR;
  2428.     if ((k&KCTRL)!=0 && rbal>='@' && rbal<='_') /* ASCII-ify.    */
  2429.         rbal -= '@';
  2430.  
  2431.     /* See if there is a matching character -- default to the same */
  2432.  
  2433.     lbal = rbal;
  2434.     for (i = 0; bal[i].right != '\0'; i++)
  2435.         if (bal[i].right == rbal) {
  2436.             lbal = bal[i].left;
  2437.             break;
  2438.         }
  2439.  
  2440.     /* Move behind the inserted character.  We are always guaranteed    */
  2441.     /* that there is at least one character on the line, since one was  */
  2442.     /* just self-inserted by blinkparen.                    */
  2443.  
  2444.     clp = curwp->w_dotp;
  2445.     cbo = curwp->w_doto - 1;
  2446.  
  2447.     depth = 0;            /* init nesting depth        */
  2448.  
  2449.     for (;;) {
  2450.         if (cbo == 0) {            /* beginning of line    */
  2451.             clp = lback(clp);
  2452.             if (clp == curbp->b_linep)
  2453.                 return (FALSE);
  2454.             cbo = llength(clp)+1;
  2455.         }
  2456.         if (--cbo == llength(clp))    /* end of line        */
  2457.             c = '\n';
  2458.         else
  2459.             c = lgetc(clp,cbo);    /* somewhere in middle    */
  2460.  
  2461.         /* Check for a matching character.  If still in a nested */
  2462.         /* level, pop out of it and continue search.  This check */
  2463.         /* is done before the nesting check so single-character     */
  2464.         /* matches will work too.                 */
  2465.         if (c == lbal) {
  2466.             if (depth == 0) {
  2467.                 displaymatch(clp,cbo);
  2468.                 return (TRUE);
  2469.             }
  2470.             else
  2471.                 depth--;
  2472.         }
  2473.         /* Check for another level of nesting.  */
  2474.         if (c == rbal)
  2475.             depth++;
  2476.     }
  2477. }
  2478.  
  2479.  
  2480. /*
  2481.  * Display matching character.
  2482.  * Matching characters that are not in the current window
  2483.  * are displayed in the echo line. If in the current
  2484.  * window, move dot to the matching character,
  2485.  * sit there a while, then move back.
  2486.  */
  2487.  
  2488. static displaymatch(clp, cbo)
  2489. register LINE *clp;
  2490. register int  cbo;
  2491. {
  2492.     register LINE    *tlp;
  2493.     register int    tbo;
  2494.     register int    cp;
  2495.     register int    bufo;
  2496.     register int    c;
  2497.     int        inwindow;
  2498.     char         buf[NLINE];
  2499.  
  2500.     /* Figure out if matching char is in current window by    */
  2501.     /* searching from the top of the window to dot.        */
  2502.  
  2503.     inwindow = FALSE;
  2504.     for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); tlp = lforw(tlp))
  2505.         if (tlp == clp)
  2506.             inwindow = TRUE;
  2507.  
  2508.     if (inwindow == TRUE) {
  2509.         tlp = curwp->w_dotp;    /* save current position */
  2510.         tbo = curwp->w_doto;
  2511.  
  2512.         curwp->w_dotp  = clp;    /* move to new position */
  2513.         curwp->w_doto  = cbo;
  2514.         curwp->w_flag |= WFMOVE;
  2515.  
  2516.         update();        /* show match */
  2517.         sleep(1);        /* wait a bit */
  2518.  
  2519.         curwp->w_dotp   = tlp;    /* return to old position */
  2520.         curwp->w_doto   = tbo;
  2521.         curwp->w_flag  |= WFMOVE;
  2522.         update();
  2523.     }
  2524.     else {    /* match not in this window so display line in echo area */
  2525.         bufo = 0;
  2526.         for (cp = 0; cp < llength(clp); cp++) {    /* expand tabs    */
  2527.             c = lgetc(clp,cp);
  2528.             if (c != '\t')
  2529.                 buf[bufo++] = c;
  2530.             else
  2531.                 do {
  2532.                     buf[bufo++] = ' ';
  2533.                 } while (bufo & 7);
  2534.         }
  2535.         buf[bufo++] = '\0';
  2536.         ewprintf("Matches %s",buf);
  2537.     }
  2538.     return (TRUE);
  2539. }
  2540. SHAR_EOF
  2541. fi # end of overwriting check
  2542. #    End of shell archive
  2543. exit 0
  2544.  
  2545.